package com.shuyun.ccms.encrypt.data.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.shuyun.ccms.encrypt.common.DataCheck;
import com.shuyun.ccms.encrypt.common.DataLoad;
import com.shuyun.ccms.encrypt.common.ExecuteShell;
import com.shuyun.ccms.encrypt.common.FileName;
import com.shuyun.ccms.encrypt.common.PlatForm;
import com.shuyun.ccms.encrypt.common.Table;
import com.shuyun.ccms.encrypt.common.TargetTable;
import com.shuyun.ccms.encrypt.data.EncryptProcessor;
import com.shuyun.ccms.encrypt.data.task.WriteCustomerPhoneTask;
import com.shuyun.ccms.encrypt.util.ConnectionUtil;
import com.shuyun.ccms.encrypt.util.PropertyUtil;
import com.shuyun.ccms.encrypt.util.SqlFileExecutor;


@Component
public class EncryptCustomerPhoneProcessor extends EncryptProcessor {
	private Logger logger = LoggerFactory.getLogger(EncryptCustomerPhoneProcessor.class);
	private static BlockingQueue<Map<String,String>> queue = new ArrayBlockingQueue<Map<String,String>>(40);
	private Connection conn;

	// 每隔3小时执行一次
	  @Scheduled(cron = "* * */4 * * ? ")
	// 每晚7点执行一次
//	@Scheduled(cron = "0 50 18 * * ? ")
	//测试用
	//@Scheduled(cron = "0 35 19 * * ? ")
	@Override
	public void execute() throws Exception {
		BufferedReader br = null;
		logger.info("加密客户手机号码开始.");
		long start = System.currentTimeMillis();
		int count = 1;
		String tenantId = null;

		try{
			String tenantFile = PropertyUtil.getValue("tenantId.path");
			br = new BufferedReader(new InputStreamReader(new FileInputStream(tenantFile)));
			tenantId = br.readLine();
			ExecutorService executorService = Executors.newFixedThreadPool(5);
			while(tenantId != null){
				long tenantStart = System.currentTimeMillis();
				//step1: get conn
				conn = ConnectionUtil.newInstance().getTenantConn(tenantId);

				// step2: create table
				boolean result = DataCheck.checkTableExist(conn, TargetTable.TAOBAO_CUSTOMER_INFO.getValue());
				if(!result){
					 new SqlFileExecutor().executeByClasspathFile(conn, "sql/customer_info.sql");
					 new SqlFileExecutor().executeByClasspathFile(conn, "sql/init_log.sql");
				     conn.commit();
				}

		    	// step 3: 加密当当客户数据
				result = DataCheck.checkTableExist(conn, Table.DD.getValue());
		    	if(result){
		    		boolean checkRelData = DataCheck.checkRelationTableData(conn, TargetTable.DD_CUSTOMER_PHONE.getValue());
		    		if(!checkRelData){
				       	ExecuteShell.executePhoneShell(PlatForm.DD.getValue());
		    			loadPhoneData(tenantId,count,executorService,PlatForm.DD.getValue(),TargetTable.DD_CUSTOMER_PHONE.getValue());
		    		}
		    	}

		        // step 4: 加密苏宁客户数据
		    	result = DataCheck.checkTableExist(conn, Table.SUNING.getValue());
		    	if(result){
		    		boolean checkRelData = DataCheck.checkRelationTableData(conn, TargetTable.SUNING_CUSTOMER_PHONE.getValue());
		    		if(!checkRelData){
				      	ExecuteShell.executePhoneShell(PlatForm.SUNING.getValue());
		    			loadPhoneData(tenantId,count,executorService,PlatForm.SUNING.getValue(),TargetTable.SUNING_CUSTOMER_PHONE.getValue());
		    		}
		    	}

		        // step 5: 加密一号店客户数据
		    	result = DataCheck.checkTableExist(conn, Table.YHD.getValue());
		    	if(result){
		    		boolean checkRelData = DataCheck.checkRelationTableData(conn, TargetTable.YHD_CUSTOMER_PHONE.getValue());
		    		if(!checkRelData){
				     	ExecuteShell.executePhoneShell(PlatForm.YHD.getValue());
		    			loadPhoneData(tenantId,count,executorService,PlatForm.YHD.getValue(),TargetTable.YHD_CUSTOMER_PHONE.getValue());
		    		}
		    	}

		    	// step 6: 加密京东客户数据
		    	result = DataCheck.checkTableExist(conn, Table.JD.getValue());
		    	if(result){
		    		boolean checkRelData = DataCheck.checkRelationTableData(conn, TargetTable.JD_CUSTOMER_PHONE.getValue());
		    		if(!checkRelData){
		    		  	ExecuteShell.executePhoneShell(PlatForm.JD.getValue());
				        loadPhoneData(tenantId,count,executorService,PlatForm.JD.getValue(),TargetTable.JD_CUSTOMER_PHONE.getValue());
		    		}
		    	}

		    	// step 7: 加密淘宝客户数据
				result = DataCheck.checkTableExist(conn, Table.TAOBAO.getValue());
		    	if(result){
		    		boolean checkRelData = DataCheck.checkRelationTableData(conn, TargetTable.TAOBAO_CUSTOMER_PHONE.getValue());
		    		if(!checkRelData){
			    	 	ExecuteShell.executePhoneShell(PlatForm.TAOBAO.getValue());
				        loadPhoneData(tenantId,count,executorService,PlatForm.TAOBAO.getValue(),TargetTable.TAOBAO_CUSTOMER_PHONE.getValue());
		    		}
		    	}
				long tenantEnd = System.currentTimeMillis();
				logger.info("第 " + count +  " 个租户: " + tenantId + "加密手机号码结束,耗时:" + (tenantEnd - tenantStart)/1000 +" s");
				tenantId = br.readLine();
				count++;
			}
			executorService.shutdown();

			// 删除加密过程产生的文本文件
			ExecuteShell.executeCleanShell(FileName.CUSTOMER_MOBILE.getValue());

			long end = System.currentTimeMillis();
			logger.info("=========== 所有租户加密客户手机号码结束.总耗时: "+ (end-start)/1000 +" s,共加密: " + (count-1) + "个租户");
		}catch(Exception e){
			logger.info("加密客户手机号码失败. tenantId: " + tenantId +",error:" + e.getMessage());
			throw e;
		}finally{
			ConnectionUtil.newInstance().closeConn(conn);
			if(br != null){
				br.close();
			}
		}
	}

	private void loadPhoneData(String tenantId, int count,ExecutorService executorService,String platForm, String targetTableName) throws Exception{
		logger.info("第 " + count +  " 个租户: " + tenantId + ",加载平台： " + platForm +",手机号码开始");

		long tenStart = System.currentTimeMillis();
		List<String> targetFileList = Lists.newArrayList();
		targetFileList = prepareTargetFile(platForm, tenantId);

		// 加密历史数据
		int originSize = queue.size();
		CountDownLatch latch = new CountDownLatch(originSize);
		for(int i = 0 ; i < originSize; i++){
			executorService.submit(new WriteCustomerPhoneTask(queue,latch));
		}
		latch.await();
		conn.setAutoCommit(false);
		targetFileList.stream().forEach(file ->{
		    DataLoad.loadPhoneInfo(conn, file,targetTableName,platForm);
		});
		long loadEnd = System.currentTimeMillis();
		logger.info("第 " + count +  " 个租户: " + tenantId + ",加载平台： " + platForm +",手机号码到数据库结束.总耗时: "+ (loadEnd-tenStart)+" s");
	}

	private List<String> prepareTargetFile(String platForm,String tenantId) throws Exception{
		String originalFile = null;
		String filePath = PropertyUtil.getValue("file.path");
		String targetFile = null;

		List<String> targetFileList = Lists.newArrayList();
		originalFile = filePath + "/test/data/" + tenantId + "/" + FileName.ORIGINAL.getValue() + "/" + platForm + "/" + FileName.CUSTOMER_MOBILE.getValue();
		File directory = new File(originalFile);
		File[] files = directory.listFiles();
		try {
			for(File file : files){
				targetFile = filePath + "/test/data/" + tenantId + "/" + FileName.TARGET.getValue() + "/"+ platForm + "/" +  FileName.CUSTOMER_MOBILE.getValue() +  "/" +  FileName.CUSTOMER_MOBILE.getValue()+ "_" +  UUID.randomUUID().toString().replace("-", "") + ".txt";
				Map<String,String> fileMap = Maps.newConcurrentMap();
				fileMap.put("fileName", file.getAbsolutePath());
				fileMap.put("targetFile", targetFile);
				targetFileList.add(targetFile);
				queue.add(fileMap);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.info("读取租户:" + tenantId + ",平台: " + platForm + ",原始文件失败. originalFile: " + originalFile);
			throw new Exception("读取租户:" + tenantId + ",平台: " + platForm + ",原始文件失败. originalFile: " + originalFile + ",错误: " + e.getMessage());
		}
		return targetFileList;
	}

}
